package neptune.web.client.view.components;

import neptune.web.client.WebInterface;
import neptune.web.client.callback.TopologyUploadCallback;
import neptune.web.client.callback.XMLtopologyUploadCallback;
import neptune.web.client.controller.DescriptorUploadController;
import neptune.web.client.model.topology.SerializableTopology;
import neptune.web.client.services.experiment.ExperimentService;
import neptune.web.client.services.experiment.TemplateService;
import neptune.web.client.view.ConsoleManager;
import neptune.web.client.view.components.dialogs.SaveAsTemplateDialog;
import neptune.web.client.view.components.editor.TopologyEditor;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.*;

/**
 * 
 * @author Roberto Bifulco [info@RobertoBifulco.it] [RobertoBifulco.it]
 * @author Luigi Lorenzo Arpino [luigiarpino@yhaoo.it]
 * 
 */
public class TopologyPanel extends Composite  implements DisclosureHandler
{

	/**
	 * Restituisce il testo contenuto nella textArea
	 * 
	 * @return il testo contenuto nella textArea
	 */
    public static native  String getXMLtext() /*-{
	    try
	    {
			return $wnd.editAreaLoader.getValue("xmlEditor");    
		}
		catch ( e )
		{
			return "unknown";
		}
	}-*/;
    
	/**
	 * Inizializza la text Area
	 * @return
	 */
    public static native void inizializedTextBox() /*-{
            try {
            		$wnd.editAreaLoader.init({
						id: "xmlEditor"			
						,start_highlight: true	
						,allow_resize: "both"
						,allow_toggle: false
						,is_multi_files: false
						,font_size: "12"
						,language: "en"
						,syntax: "xml"	
					});
                    
            } catch ( e ) {  }
    }-*/;
    
    
	/**
     * Inserisce del testo nella textArea
     * 
     * @param xmlText il testo da inserire
     */
    public static native void setXMLtext(String xmlText) /*-{
        try
	    {
			return $wnd.editAreaLoader.setValue("xmlEditor", xmlText);   
		}
		catch ( e )
		{
			
		}
	}-*/;

	public final String topologyUploadServiceUrl = GWT.getModuleBaseURL()
			+ "uploadTopology";
	public static final String TOPOLOGY_FILE = "topologyFile";
	public static final String EXP_NAME = "experimentName";
	private FormPanel upLoadFilePanel;
	private FormHandler uploadFileFormHandler = new DescriptorUploadController(
			this);
	private FileUpload fileUploadInput; 
	
	private String expName;
	private TopologyEditor topologyEditor;
	private String xmlTopology; // La descrizione XML della topologia
	private boolean isTextBoxInizialized;
	private ListBox listaTemplate;
	private String[][] elencoTemplate;
	private HTML htmlDescTemplate;
	
	private DisclosurePanel xmlEditorWrap;
	
	private ClickListener topologyUploadListener = new ClickListener() {
		public void onClick(Widget sender) {
			uploadTopologyFromEditor();
		}
	};
	
	private ClickListener saveAsTemplateListener = new ClickListener() 
	{
		public void onClick(Widget sender) 
		{
			saveAsTemplateFromEditor();
		}
	};

	private ClickListener descriptorUploadListener = new ClickListener() {
		public void onClick(Widget sender) {
			uploadTopologySelectedFile();
		}
	};

	// L'utente fa l'upload della topologia in formato xml
	private ClickListener xmlUploadListener = new ClickListener(){
		public void onClick(Widget sender)	{
			uploadTopologyFromXMLeditor();
		}
	};
	
	// L'utente vuole utilizzare un template per il proprio progetto
	private ClickListener useTemplateListener = new ClickListener()
	{
		public void onClick(Widget sender)	
		{
			xmlEditorWrap.setOpen(false);
			// l'indice del template scelto
			int index=listaTemplate.getSelectedIndex();
			String fileName=elencoTemplate[index][0];
			TemplateService.Util.getInstance().getXMLTemplate(fileName, new AsyncCallback<String>()
			{
				public void onFailure(Throwable caught) 
				{
					WebInterface.addMessageToConsoleAndShowDialog(
							"Error while loading template file "+
							"'. Cause:\n" + caught.getMessage(), true);
				}

				public void onSuccess(String result) 
				{
					updateTopology(result);
				}
			});
			TemplateService.Util.getInstance().getTopology(fileName, new AsyncCallback<SerializableTopology>()
			{
				public void onFailure(Throwable caught) 
				{
					WebInterface.addMessageToConsoleAndShowDialog(
							"Error while loading template file "+
							"'. Cause:\n" + caught.getMessage(), true);
				}

				public void onSuccess(SerializableTopology topology) 
				{
					updateTopology(topology);
				}
			});
		}
	};
	
	

	public TopologyPanel() 
	{
		this.isTextBoxInizialized=false;

		VerticalPanel mainPanel = new VerticalPanel();
		mainPanel.setHeight("100%");
		mainPanel.setWidth("100%");

		HTML help = new HTML(
				"From this page you can edit the experiment's topology."
						+ "To define or modify the topology, "
						+ "use one of the next methods. For new users, the topology"
						+ " editor is the simplest way to start.<br/>"
						+ "Note that you can move between experiment's tab without "
						+ "loosing unsaved informations on the topology definitions, "
						+ "while if you exit this experiment view, all unsaved infos "
						+ "will be lost.");
		help.setSize("95%", "100%");
		mainPanel.add(help);
		mainPanel.setCellHorizontalAlignment(help, VerticalPanel.ALIGN_CENTER);

		// TOPOLOGY EDITOR
		DisclosurePanel topologyEditorWrap = new DisclosurePanel(
				"Topology Editor");
		topologyEditorWrap.setWidth("100%");
		Panel topologyEditorPanel = buildTopologyEditor();
		topologyEditorWrap.add(topologyEditorPanel);
		topologyEditorWrap.setAnimationEnabled(true);
		topologyEditorWrap.setOpen(true);

		// XML EDITOR
		this.xmlEditorWrap = new DisclosurePanel("XML Editor");
		this.xmlEditorWrap.setWidth("100%");
		this.xmlEditorWrap.add(buildXmlEditor());
		this.xmlEditorWrap.setAnimationEnabled(true);
		this.xmlEditorWrap.addEventHandler(this);
	
		
		// SELECT TEMPLATE
		DisclosurePanel selectTemplateWrap = new DisclosurePanel(
				"Select Template");
		selectTemplateWrap.setWidth("100%");
		selectTemplateWrap.add(buildSelectTemplatePanel());
		selectTemplateWrap.setAnimationEnabled(true);
		selectTemplateWrap.addEventHandler(new DisclosureHandler()
		{
			public void onClose(DisclosureEvent event) {}
			public void onOpen(DisclosureEvent event)
			{
				if (listaTemplate != null && listaTemplate.getItemCount()==0 )
				{
					TemplateService.Util.getInstance().getAllTemplate(new AsyncCallback<String[][]>()
					{

						public void onFailure(Throwable caught) 
						{
							WebInterface.addMessageToConsoleAndShowDialog(
									"Error while loading template list "+
									"'. Cause:\n" + caught.getMessage(), true);
						}
	
						public void onSuccess(String[][] result) 
						{
							elencoTemplate=result;
							if (elencoTemplate!=null)
							{
								htmlDescTemplate.setText(elencoTemplate[0][2]);
							}
							// NB data è una riga della matrice result
							for (String[] data : result) 
							{
								listaTemplate.addItem(data[1]);
							}
						}
					});
				}
			}
			
		});

		// UPLOAD DESCRIPTOR
		DisclosurePanel uploadDescriptorWrap = new DisclosurePanel(
				"Upload Descriptor");
		uploadDescriptorWrap.setWidth("100%");
		uploadDescriptorWrap.add(buildUploadDescriptor());
		uploadDescriptorWrap.setAnimationEnabled(true);

		mainPanel.add(topologyEditorWrap);
		mainPanel.add(xmlEditorWrap);
		mainPanel.add(selectTemplateWrap);
		mainPanel.add(uploadDescriptorWrap);

		// Styles
		mainPanel.setStylePrimaryName("TopologyPanel");
		topologyEditorWrap.setStylePrimaryName("TopologyPanel-disclosurePanel");
		xmlEditorWrap.setStylePrimaryName("TopologyPanel-disclosurePanel");
		selectTemplateWrap.setStylePrimaryName("TopologyPanel-disclosurePanel");
		uploadDescriptorWrap
				.setStylePrimaryName("TopologyPanel-disclosurePanel");
		help.setStylePrimaryName("TopologyPanel-mainHelp");

		initWidget(mainPanel);
	}

	/**
     * Restituisce il pannello per la gestione dei template
     * 
     * @return
     */
	private Panel buildSelectTemplatePanel()
	{
		VerticalPanel vPanel = new VerticalPanel();
		vPanel.setSize("95%", "100%");

		HTML help = new HTML("The template selector provides a simple "
				+ "way to define a topology.<br>"		
				+ "You can use a template to help you to describe your project.<br>"
				+"After, you can customize the XML description in \"XML Editor\" or "+
				" you can use \"Topology Editor\" ( WYSIWYG editor )<br><br>");
				
		
		help.setStylePrimaryName("TopologyPanel-help");
		vPanel.add(help);
		
		HorizontalPanel panelLabel=new HorizontalPanel();
		Label labelDescrizioneTemplate=new Label("\nDescription of template:");
		panelLabel.add(labelDescrizioneTemplate);
		vPanel.add(panelLabel);
		
		this.htmlDescTemplate=new HTML();
		this.htmlDescTemplate.setStylePrimaryName("TopologyPanel-help");
		htmlDescTemplate.setHTML("<b>Sorry not yet template avaiable!</b>");
		vPanel.add(this.htmlDescTemplate);

		HorizontalPanel panel=new HorizontalPanel();
		if (this.listaTemplate==null)
		{
			this.listaTemplate=new ListBox();
			this.listaTemplate.addChangeListener(new ChangeListener()
			{
				public void onChange(Widget sender) 
				{
					int index=((ListBox)sender).getSelectedIndex();
					htmlDescTemplate.setText(elencoTemplate[index][2]);
				}
			});
		}
		panel.add(this.listaTemplate);
		vPanel.add(panel);
		
		HorizontalPanel commandsPanel = new HorizontalPanel();

		Button buttonUseTemplate = new Button("Use Template");
		buttonUseTemplate.setTitle("Click to use this template for your project");
		buttonUseTemplate.setStylePrimaryName("TopologyPanel-commandsPanel-button");
		buttonUseTemplate.addClickListener( useTemplateListener );
		commandsPanel.add(buttonUseTemplate);
		
		vPanel.add(commandsPanel);
		vPanel.setCellHorizontalAlignment(commandsPanel, VerticalPanel.ALIGN_LEFT);

		commandsPanel.setStylePrimaryName("TopologyPanel-commandsPanel");
		return vPanel;
	}

	/**
	 * Costruisce il pannello Topology Editor
	 * che descrive  
	 * @return
	 */
	private Panel buildTopologyEditor() {
		VerticalPanel vPanel = new VerticalPanel();
		vPanel.setSize("95%", "100%");

		HTML help = new HTML("The topology editor provides a simple "
				+ "way to define or modify a topology. Using the topology "
				+ "tree showed on the left side of the editor, every topology"
				+ " component can be modified."
				+ " When the topology is completed, it can be uploaded on the "
				+ "server for validation and saving. Please note that only a "
				+ "valid topology is actually saved on the server.<br/<br/>"
				+ "The topology editor helps the definition of the topology "
				+ "automatically generating nodes, network interfaces and "
				+ "links names. Moreover, it defines for every network "
				+ "interface a MAC address (editable by the user). It's "
				+ "also possible to define IP addresses for network "
				+ "interfaces, but this feature is intended for advanced "
				+ "uses, from expert users. If you don't know how to "
				+ "assign a correct IP address to respect the topology "
				+ "correctness just don't define ip addresses: the "
				+ "system automatically generates any address. ");
		help.setStylePrimaryName("TopologyPanel-help");
		vPanel.add(help);

		topologyEditor = new TopologyEditor();
		vPanel.add(topologyEditor);

		HorizontalPanel commandsPanel = new HorizontalPanel();

		Button topologyUploadButton = new Button("Upload to server");
		topologyUploadButton.setTitle("Upload the topology on server");
		topologyUploadButton
				.setStylePrimaryName("TopologyPanel-commandsPanel-button");
		topologyUploadButton.addClickListener(topologyUploadListener);
		commandsPanel.add(topologyUploadButton);
		
		Button buttonSaveAsTemplate = new Button("Save template");
		buttonSaveAsTemplate.setTitle("save the topology as a template on server");
		buttonSaveAsTemplate.setStylePrimaryName("TopologyPanel-commandsPanel-button");
		buttonSaveAsTemplate.addClickListener(saveAsTemplateListener);
		commandsPanel.add(buttonSaveAsTemplate);
		
		vPanel.add(commandsPanel);
		vPanel.setCellHorizontalAlignment(commandsPanel,
				VerticalPanel.ALIGN_LEFT);

		commandsPanel.setStylePrimaryName("TopologyPanel-commandsPanel");

		return vPanel;
	}
	
	private FormPanel buildUploadDescriptor() {
		upLoadFilePanel = new FormPanel();
		upLoadFilePanel.setAction(topologyUploadServiceUrl);
		upLoadFilePanel.setMethod(FormPanel.METHOD_POST);
		// Poiche' si invia un file si adopera l'encoding multipart
		upLoadFilePanel.setEncoding(FormPanel.ENCODING_MULTIPART);
		upLoadFilePanel.addFormHandler(uploadFileFormHandler);

		VerticalPanel vPanel = new VerticalPanel();
		vPanel.setSize("95%", "100%");

		HorizontalPanel hPanel = new HorizontalPanel();
		hPanel.setWidth("100%");
		Label fileLabel = new Label("Topology file:");
		fileUploadInput = new FileUpload();
		fileUploadInput.setName(TOPOLOGY_FILE);
		// Width setting for IE
		fileUploadInput.setWidth("100%");
		// Width setting for FF
		fileUploadInput.getElement().setAttribute("size", "100%");

		hPanel.add(fileLabel);
		hPanel.add(fileUploadInput);
		hPanel.setCellWidth(fileLabel, "30%");
		hPanel.setCellWidth(fileUploadInput, "70%");
		hPanel.setCellHorizontalAlignment(fileUploadInput,
				HasHorizontalAlignment.ALIGN_LEFT);

		HTML help = new HTML("If you have a topology descriptor "
				+ "file, you can upload it using this function. "
				+ "The topology descriptor"
				+ " is processed to verify the correctness of "
				+ "the descripted topology. "
				+ "If the topology is valid, it will"
				+ " be saved on the server.");
		help.setStylePrimaryName("TopologyPanel-help");
		vPanel.add(help);

		vPanel.add(hPanel);
		upLoadFilePanel.setWidget(vPanel);

		HorizontalPanel commandsPanel = new HorizontalPanel();

		Button uploadButton = new Button("Upload");
		uploadButton.setStylePrimaryName("TopologyPanel-commandsPanel-button");
		uploadButton.addClickListener(descriptorUploadListener);
		commandsPanel.add(uploadButton);

		vPanel.add(commandsPanel);
		vPanel.setCellHorizontalAlignment(commandsPanel,
				VerticalPanel.ALIGN_RIGHT);

		// Styles
		upLoadFilePanel.setStylePrimaryName("UploadPanel");
		hPanel.setStylePrimaryName("HorizontalPanel");
		fileUploadInput.setStylePrimaryName("FileUploadInput");
		commandsPanel.setStylePrimaryName("TopologyPanel-commandsPanel");

		return upLoadFilePanel;
	}

	private Panel buildXmlEditor()
	{
		VerticalPanel vPanel = new VerticalPanel();
		vPanel.setSize("95%", "100%");

		HTML help = new HTML("The xml topology editor provides a simple "
				+ "way to define a topology.<br>"		
				+ "When the editing is completed, it can be uploaded on the "
				+ "server for validation and saving.<br>" 
				+ "<b>Please note that only a valid topology is actually"
				+ " saved on the server.</b><br>");
	
		
		help.setStylePrimaryName("TopologyPanel-help");
		vPanel.add(help);

		HTML html=new HTML();
		
		String stHTML="<textarea id=\"xmlEditor\" style=\"height: 500px; width: 700px;\" name=\"test_1\">";
		html.setHTML(stHTML);
		vPanel.add(html);
		
		HorizontalPanel commandsPanel = new HorizontalPanel();

		Button topologyUploadButton = new Button("Upload");
		topologyUploadButton.setStylePrimaryName("TopologyPanel-commandsPanel-button");
		topologyUploadButton.addClickListener( xmlUploadListener );
		commandsPanel.add(topologyUploadButton);
		/*
		Button buttonLoadTopology = new Button("Load");
		buttonLoadTopology.setStylePrimaryName("TopologyPanel-commandsPanel-button");
		//buttonLoadTopology.addClickListener
		gg
		commandsPanel.add(buttonLoadTopology);
		*/
		vPanel.add(commandsPanel);
		vPanel.setCellHorizontalAlignment(commandsPanel, VerticalPanel.ALIGN_LEFT);

		commandsPanel.setStylePrimaryName("TopologyPanel-commandsPanel");
		return vPanel;
	}

	public String getExpName() {
		return expName;
	}

	public FileUpload getFileUploadInput() {
		return fileUploadInput;
	}

	public FormPanel getUpLoadFilePanel() {
		return upLoadFilePanel;
	}

	/* (non-Javadoc)
	 * @see com.google.gwt.user.client.ui.DisclosureHandler#onClose(com.google.gwt.user.client.ui.DisclosureEvent)
	 */
	public void onClose(DisclosureEvent event)
	{
		
	}
	
	
	/* (non-Javadoc)
	 * @see com.google.gwt.user.client.ui.DisclosureHandler#onOpen(com.google.gwt.user.client.ui.DisclosureEvent)
	 */
	public void onOpen(DisclosureEvent event) 
	{
		if ( !this.isTextBoxInizialized )
		{
			inizializedTextBox();
		}
		this.isTextBoxInizialized=true;
		// se è presente la descrizione di una topologia
		if (this.xmlTopology != null)
		{
			setXMLtext(this.xmlTopology);
		}
	}
    
    
    public void reset() 
    {
		expName = "";
		topologyEditor.reset();
		this.xmlTopology="";
		this.xmlEditorWrap.setOpen(false);
	}
    
    
    public void setExpName(String expName) {
		this.expName = expName;
	}
    
    public void useTemplate()
    {
    	
    }
    
    
    public void updateTopology(SerializableTopology topology)
    {
		topologyEditor.setTopology(topology);
	}
    
    public void updateTopology(String xmlTopology)
    {
    	/*
    	System.out.println();
    	System.out.println(" *** ");
    	System.out.println();
    	String result=xmlTopology;
		for (int i=0 ; i<result.length() ; i++)
		{
			System.out.println(result.codePointAt(i)+" --> "+result.charAt(i));
		}
		System.out.println();
    	System.out.println(" *** ");
    	System.out.println();
		*/
    	this.xmlEditorWrap.setOpen(false);
    	this.xmlTopology=xmlTopology;
    }
	

	public void uploadTopologyFromEditor()
	{
		this.xmlEditorWrap.setOpen(false);
		String message = "Saving topology on server...";
		ConsoleManager.addConsoleMessage(message, false);

		final PopupPanel loadingPopup = WebInterface.showMessageDialog(
				new MessageWidget(MessageWidget.LOADING, message), false);

		topologyEditor.getTopology().setName(expName);
		ExperimentService.Util.getInstance().uploadExperimentTopology(expName,
				topologyEditor.getTopology(),
				new TopologyUploadCallback(expName, loadingPopup));
	}
	
	
	private void saveAsTemplateFromEditor() 
	{
		SerializableTopology serTopology = topologyEditor.getTopology();
		SaveAsTemplateDialog dialog = new SaveAsTemplateDialog(serTopology);
		dialog.center();
	}

	/**
	 * Invia il contenuto dell'editor xml al server
	 */
	public void uploadTopologyFromXMLeditor()
	{
		String message = "Saving topology on server...";
		ConsoleManager.addConsoleMessage(message, false);
		//TODO settare il nome dell'esperimento
		
		final PopupPanel loadingPopup = WebInterface.showMessageDialog(
				new MessageWidget(MessageWidget.LOADING, message), false);
		
		ExperimentService.Util.getInstance().uploadExperimentXMLTopology(expName, getXMLtext(), new XMLtopologyUploadCallback(expName,loadingPopup));
	}

	/**
	 * Invia il file selezionato, tramite il pannello UploadFile, al server.
	 */
	public void uploadTopologySelectedFile() {
		// Comunica al server il nome dell'esperimento cui appartiene la
		// topologia in upload
		((Panel) upLoadFilePanel.getWidget())
				.add(new Hidden(EXP_NAME, expName));
		upLoadFilePanel.submit();
	}
	
}
